using UnityEngine;
using System;
using System.IO;
using UnityEditor;
using System.Text;
using System.Collections.Generic;
using System.Xml;
using System.Diagnostics;
using System.Linq;

namespace BToolkit
{
    public class TexturePacker : Editor
    {
        //插件安装路径
        const string KEY_EXE_PATH_CACHE = "KEY_PACKER_CACHE";
        private static string packerExePath
        {
            get { return PlayerPrefs.GetString(KEY_EXE_PATH_CACHE); }
            set { PlayerPrefs.SetString(KEY_EXE_PATH_CACHE, value); }
        }
        //限制进入图集图片宽高
        private static int limitW = 500;
        private static int limitH = 500;
        private static List<string> extensionlist = new List<string>() { ".png", ".tga", ".jpg", };

        [MenuItem("Assets/TexturePacker")]
        public static void StartPack()
        {
            if (string.IsNullOrEmpty(packerExePath))
            {
                if (EditorUtility.DisplayDialog("提示", "首次使用请先安装 TexturePacker，并指定\n\n安装目录下的 bin/TexturePacker.exe。", "立即指定"))
                {
                    packerExePath = EditorUtility.OpenFilePanel("选择文件", "C:/", "exe");
                }
                else
                {
                    return;
                }
            }
            UnityEngine.Object[] objs = Selection.GetFiltered(typeof(DefaultAsset), SelectionMode.Assets);
            if (objs.Length == 0)
            {
                UnityEngine.Debug.Log("请选择一个包含字体图片的目录");
                return;
            }
            if (objs.Length > 1)
            {
                UnityEngine.Debug.Log("只能选择一个目录");
                return;
            }

            string inputPath = Application.dataPath.Replace("Assets", "") + AssetDatabase.GetAssetPath(objs[0]);
            string outputPath = inputPath;
            if (Directory.Exists(inputPath))
            {
                //删除旧文件，否则报错
                string filename = inputPath.Split('/').Last();
                string filePath = inputPath + "/" + filename + ".png";
                if (File.Exists(filePath)) AssetDatabase.DeleteAsset(filePath.Substring(filePath.IndexOf("Assets/")));
                //开始打包
                Pack(inputPath, outputPath);
            }
            else
            {
                UnityEngine.Debug.LogError("请选中要打包图集的文件夹");
            }
        }

        private static void Pack(string inputPath, string outputPath)
        {
            string commandText = " --sheet {0}.png --data {1}.xml --format sparrow --trim-mode None --pack-mode Best  --algorithm MaxRects --max-size 2048 --size-constraints POT  --disable-rotation --scale 1 {2}";
            string[] fileName = Directory.GetFiles(inputPath + "/", "*.*");
            string filename = inputPath.Split('/').Last();
            StringBuilder sb = new StringBuilder("");
            Dictionary<string, string> lt = new Dictionary<string, string>();
            for (int j = 0; j < fileName.Length; j++)
            {
                string filepath = fileName[j];
                string extenstion = System.IO.Path.GetExtension(filepath);
                if (filepath.Contains(" "))
                {
                    UnityEngine.Debug.LogError("包含空格:" + filepath);
                    continue;
                }
                if (extensionlist.Contains(extenstion))
                {
                    Texture2D texture = GetTexture(filepath);
                    int with = texture.width;
                    int height = texture.height;
                    bool limit = with <= limitW && height <= limitH;
                    if (limit && extenstion == ".png") //写死 只有PNG才能打图集
                    {
                        sb.Append(filepath);
                        sb.Append("  ");
                    }
                    else
                    {
                        string newfilepath = string.Format("{0}/{1}", outputPath, Path.GetFileName(filepath));
                        lt.Add(filepath, newfilepath);
                    }
                }

            }
            string sheetName = string.Format(outputPath + "/{0}", filename);
            //执行命令行
            ProcessCommand(packerExePath, string.Format(commandText, sheetName, sheetName, sb.ToString()));
            foreach (string key in lt.Keys)
            {
                File.Copy(key, lt[key], true);
                if (!File.Exists(lt[key] + ".meta"))
                {
                    File.Copy(key + ".meta", lt[key] + ".meta", true);//保持原先的设置信息
                }
            }
            AssetDatabase.Refresh();
            BuildSplitTexturePacker(sheetName, inputPath);
        }

        private static void ProcessCommand(string command, string argument)
        {
            ProcessStartInfo start = new ProcessStartInfo(command);
            start.Arguments = argument;
            start.CreateNoWindow = false;
            start.ErrorDialog = true;
            start.UseShellExecute = false;
            if (start.UseShellExecute)
            {
                start.RedirectStandardOutput = false;
                start.RedirectStandardError = false;
                start.RedirectStandardInput = false;
            }
            else
            {
                start.RedirectStandardOutput = true;
                start.RedirectStandardError = true;
                start.RedirectStandardInput = true;
                start.StandardOutputEncoding = Encoding.UTF8;
                start.StandardErrorEncoding = Encoding.UTF8;
            }
            Process p = Process.Start(start);
            if (!start.UseShellExecute)
            {
                //UnityEngine.Debug.Log(p.StandardOutput.ReadToEnd());
                UnityEngine.Debug.Log(p.StandardError.ReadToEnd());
            }
            p.WaitForExit();
            p.Close();
        }

        public static void BuildSplitTexturePacker(string rootPath, string selectpath)
        {
            string pngPath = string.Format("{0}.png", rootPath);
            Texture2D texture = GetTexture(pngPath);
            Dictionary<string, Vector4> tIpterMap = new Dictionary<string, Vector4>();
            if (File.Exists(pngPath))
            {
                TextureImporter asetImp = GetTextureIpter(texture);
                SaveBoreder(tIpterMap, asetImp);
                asetImp.SaveAndReimport();
            }
            else
            {
                UnityEngine.Debug.LogError("生成的文件不存在:" + pngPath);
                return;
            }
            AssetDatabase.Refresh();
            string xmlpath = string.Format("{0}.xml", rootPath);
            FileStream fs = new FileStream(xmlpath, FileMode.Open);
            StreamReader sr = new StreamReader(fs);
            string jText = sr.ReadToEnd();
            fs.Close();
            sr.Close();
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(jText);
            XmlNodeList elemList = xml.GetElementsByTagName("SubTexture");
            WriteMeta(elemList, pngPath, selectpath, texture.height, tIpterMap);
            ClearXmlFile(xmlpath);
            AssetDatabase.Refresh();
        }

        //如果这张图集已经拉好了9宫格，需要先保存起来
        static void SaveBoreder(Dictionary<string, Vector4> tIpterMap, TextureImporter tIpter)
        {
            for (int i = 0, size = tIpter.spritesheet.Length; i < size; i++)
            {
                tIpterMap.Add(tIpter.spritesheet[i].name, tIpter.spritesheet[i].border);
            }
        }

        static Texture2D GetTexture(string path)
        {
            Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(GetAssetPath(path));
            return texture;
        }
        static TextureImporter GetTextureIpter(Texture2D texture)
        {
            TextureImporter textureIpter = null;
            string impPath = AssetDatabase.GetAssetPath(texture);
            textureIpter = TextureImporter.GetAtPath(impPath) as TextureImporter;
            textureIpter.alphaIsTransparency = true;
            textureIpter.mipmapEnabled = false;
            return textureIpter;
        }

        static TextureImporter GetTextureIpterAll(string path)
        {
            Texture2D textureOrg = GetTexture(path);
            TextureImporter textureIpter = GetTextureIpter(textureOrg);
            textureIpter.alphaIsTransparency = true;
            textureIpter.mipmapEnabled = false;
            return textureIpter;
        }

        /// 清理xml
        private static void ClearXmlFile(string filepath)
        {
            if (File.Exists(filepath))
            {
                int index = filepath.IndexOf("Assets");
                string sb = filepath.Substring(index);
                AssetDatabase.DeleteAsset(sb);
            }
        }


        //写信息到SpritesSheet里
        static void WriteMeta(XmlNodeList elemList, string path, string selectpath, int height, Dictionary<string, Vector4> borders)
        {
            string impPath = GetAssetPath(path);
            TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;
            SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];
            for (int i = 0, size = elemList.Count; i < size; i++)
            {
                XmlElement node = (XmlElement)elemList.Item(i);
                Rect rect = new Rect();
                rect.x = int.Parse(node.GetAttribute("x"));
                rect.y = height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));
                rect.width = int.Parse(node.GetAttribute("width"));
                rect.height = int.Parse(node.GetAttribute("height"));
                metaData[i].rect = rect;
                metaData[i].pivot = new Vector2(0.5f, 0.5f);
                metaData[i].name = node.GetAttribute("name");
                //读取源文件的meta文件，获取spriteBorder九宫信息，写进图集中
                string _path = string.Format(selectpath + "/{0}.png", node.GetAttribute("name"));
                Vector4 _border = GetTextureIpterAll(_path).spriteBorder;
                metaData[i].border = _border;
            }
            asetImp.spritesheet = metaData;
            asetImp.textureType = TextureImporterType.Sprite;
            asetImp.spriteImportMode = SpriteImportMode.Multiple;
            asetImp.mipmapEnabled = false;
            EditorUtility.SetDirty(asetImp);
            asetImp.SaveAndReimport();
        }

        static string GetAssetPath(string path)
        {
            string[] seperator = { "Assets" };
            string p = "Assets" + path.Split(seperator, StringSplitOptions.RemoveEmptyEntries)[1];
            return p;
        }
    }
}